package edu.isistan.parser;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;


import com.thoughtworks.qdox.JavaDocBuilder;
import com.thoughtworks.qdox.model.DocletTag;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaMethod;
import com.thoughtworks.qdox.model.JavaParameter;
import com.thoughtworks.qdox.model.Type;

import edu.isistan.metamodel.DataType;
import edu.isistan.metamodel.Interface;
import edu.isistan.metamodel.Operation;
/**
 * Parses a .java file
 */
public class JavaParser implements Parser {
	
	/**
	 * Profundidad de busqueda de los tipos de datos primitivos
	 */
	public static int PARAMETERS_DEPTH = 8;
	
	
	public JavaDocBuilder javaDocBuilder;
	private JavaClass javaClass;
	private DataTypeMetamodelTransformer dataTypeMetamodelTransformer;
	private String parentFolderPath = null;
	
	public JavaParser() {	
	}
	
	/** 
	 * Parses the .java
	 * @param fileName the path file
	 * @return true if success
	 */
	protected boolean parse(String fileName){
		try {
			javaDocBuilder = new JavaDocBuilder();
			javaDocBuilder.addSource(new FileReader(fileName));
			javaClass = javaDocBuilder.getClasses()[0];	
			if(parentFolderPath != null )
//				javaDocBuilder.addSourceTree(new File(parentFolderPath));
				javaDocBuilder.getClassLibrary().addSourceFolder(new File(parentFolderPath));
			dataTypeMetamodelTransformer =  new DataTypeMetamodelTransformer(javaDocBuilder);
		
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}	
	
	/** 
	 * Gets the metamodel from the .java
	 * @return the Interface metamodel
	 */	
	public Interface getMetamodel(String fileName){
		if (parse(fileName)) {
			Interface inf = new Interface();
			inf.setName( javaClass.getName() );
			inf.setDoc(javaClass.getComment());
			JavaMethod[] methods = javaClass.getMethods();
			for(JavaMethod method : methods){
				inf.addOperation(this.getOperation(method));
			}
			return inf;
		} else {
			return null;
		}
	}	
	
	/** 
	 * Gets the metamodel Operation from an operation
	 * @param method the method to get the metamodel
	 * @return the Operation metamodel
	 */	
	private Operation getOperation(JavaMethod method){
		Operation operation = new Operation();
		//Name
		operation.setName(method.getName());
		//Documentation
		operation.setDoc(method.getComment());
		//Return				
		Type returnType = method.getReturnType();
		DataType returnDataType = dataTypeMetamodelTransformer.getDataType(returnType,null ,PARAMETERS_DEPTH);
		DocletTag[] returnDoc = method.getTagsByName("return");
		if(returnDoc.length!=0){
			returnDataType.setDoc(returnDoc[0].getValue());
		}
		operation.addReturnParameter(returnDataType);
		//Parameters
		JavaParameter[] parameters = method.getParameters();
		for(JavaParameter parameter : parameters){			
			DataType dataType = dataTypeMetamodelTransformer.getDataType(parameter.getType(),parameter.getName(),PARAMETERS_DEPTH);
			
			DocletTag[] params = method.getTagsByName("param");
			for(int i=0 ; i<params.length ; i++){
				if(params[i].getValue().startsWith(dataType.getName())){
					dataType.setDoc(params[i].getValue());
				}
			}
			operation.addParameter(dataType,parameter.getName());
		}		
		return operation;
	}
	
	public String getParentFolderPath() {
		return parentFolderPath;
	}
	
	public void setParentFolderPath(String parentFolderPath) {
		this.parentFolderPath = parentFolderPath;
	}

	public static void main(String[] args) {
		JavaParser p = new JavaParser();
		Interface interfaz0 = p.getMetamodel("./src/experiments/Client.java");
		System.out.println("Operaciones " + interfaz0.getOperations().toString());
		System.out.println("Primera interfaz MortagagePaymentCalculator.java" + interfaz0.toString());
		System.out.println("-------");
		Interface interfaz1 = p.getMetamodel("./src/experiments/MortgageCalculator.java");
		System.out.println(interfaz1.toString());
		System.out.println("-------");
		System.out.println(interfaz1.getOperation(0).getReturnValue().get(0));
	}
	
}
